#encoding=utf-8
from flask import Flask, request
import importlib
import os
import celery

from app.authorization.model import ManagementJWT, Management_User
from config.settings import ProductConfig, init_admin_user, init_record_event
from utils.route import RouteManageMent
from utils.ext import inner_db
from common.log.log_config import logger
from app.record.add_record import add_record

def make_app():
    app = Flask(__name__)
    app.config.from_object(ProductConfig)
    ManagementJWT(app)

    return app

def register_service_module(app):
    # 导入app目录下的所有模块
    route_base_path = "/api/v1"
    current_dir = os.path.dirname(os.path.abspath(__file__))
    app_dir = os.path.join(current_dir, "app")
    app_module = {}
    # 规则约定app目录下子目录为一个功能app
    # 每个子目录下必须包含 urls.py
    # urls.py中包含 urls_map变量
    # Blueprint以目录名称命名，然后通过urls_map变量导入路由
    for app_dir_name in os.listdir(app_dir):
        if not os.path.isdir(os.path.join(app_dir, app_dir_name)):
            continue
        if "__pycache__" == app_dir_name:
            continue
        try:
            app_module_name = "app.{}.urls".format(app_dir_name)
            logger.info("registering module {}".format(app_module_name))

            app_module[app_dir_name] = importlib.import_module(app_module_name)

            if hasattr(app_module[app_dir_name], "urls_map"):
                urls_map = getattr(app_module[app_dir_name], "urls_map")
                sub_route = RouteManageMent(app_dir_name, app_module_name, urls_map)
                app.register_blueprint(sub_route.get_route_resource(),
                                       url_prefix='{}/{}'.format(route_base_path, app_dir_name))
        except Exception as err:
            logger.info(str(err))
            raise

def init_db(app):
    try:
        inner_db.init_app(app)
        with app.app_context():
            init_admin_user(inner_db, Management_User)
            init_record_event(inner_db)
    except Exception as err:
        logger.info(str(err))
        raise

def get_token_exclude_url():
    # 导入app目录下的所有模块
    route_base_path = "/api/v1"
    current_dir = os.path.dirname(os.path.abspath(__file__))
    app_dir = os.path.join(current_dir, "app")
    # 规则约定app目录下子目录为一个功能app
    # 每个子目录下必须包含 urls.py
    # urls.py中包含 token_config变量
    token_exclude_url = ['/auth']
    for app_dir_name in os.listdir(app_dir):
        if not os.path.isdir(os.path.join(app_dir, app_dir_name)):
            continue
        if "__pycache__" == app_dir_name:
            continue
        app_module_name = "app.{}.urls".format(app_dir_name)
        app_module = importlib.import_module(app_module_name)
        if not hasattr(app_module, "token_config"):
            continue

        app_module_url_base = "{}/{}".format(route_base_path, app_dir_name)
        token_config = getattr(app_module, "token_config")
        for sub_url in token_config:
            if token_config[sub_url]:
                continue
            token_exclude_url.append("{}{}".format(app_module_url_base, sub_url))

    logger.info("token_exclude_url {}".format(token_exclude_url))

    return token_exclude_url

def set_token_check(app, token_exclude_url):
    @app.before_request
    def check_token():
        from flask import request
        if request.path in token_exclude_url:
            return None

        from flask_jwt import jwt_required
        @jwt_required()
        def inner_token_check():
            pass

        try:
            return inner_token_check()
        except Exception as e:
            return str(e), 403

def add_request_record(app):
    @app.after_request
    def request_record(response):
        return add_record(response)

# Celery Configuration
def make_celery(app, include_list):
    if not hasattr(app, 'celery'):
        celery_instance = celery.Celery('flask-celery-app',
                                        broker=app.config['CELERY_BROKER_URL'],
                                        include=include_list)
        TaskBase = celery.Task
        class ContextTask(TaskBase):
            abstract = True
            def __call__(self, *args, **kwargs):
                with app.app_context():
                    return TaskBase.__call__(self, *args, **kwargs)

        celery.Task = ContextTask

        celery_instance.conf.update(app.config)
        app.celery = celery_instance
        return celery_instance
    else:
        return  getattr(app, 'celery')

if __name__ == '__main__':
    app = make_app()
    token_exclude_url = get_token_exclude_url()
    set_token_check(app, token_exclude_url)
    register_service_module(app)
    init_db(app)
    add_request_record(app)
    make_celery(app, ['app.machine.celery_tasks'])
    app.run(host='0.0.0.0', debug=True)
